package com.shun.upms.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shun.common.R;
import com.shun.common.RC;
import com.shun.common.utils.ShunCommonUtils;
import com.shun.upms.common.UpmsConstant;
import com.shun.upms.dto.SysAdminMenuDto;
import com.shun.upms.dto.SysAdminMenuNodesDto;
import com.shun.upms.mapper.SysAdminMenuMapper;
import com.shun.upms.node.MenuTreeNode;
import com.shun.upms.node.SysMenuNode;
import com.shun.upms.service.ISysAdminMenuService;
import com.shun.upms.vo.SysAdminMenu;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author clever
 * @since 2021-09-27
 */
@Slf4j
@Service
public class SysAdminMenuServiceImpl extends ServiceImpl<SysAdminMenuMapper, SysAdminMenu> implements ISysAdminMenuService {

    @Autowired
    private SysAdminMenuMapper menuMapper;

    @Override
    public List<String> getMenuCodeByUser(String userId) {
        log.debug("userId:{}", userId);
        return menuMapper.getMenuCodesByUser(userId);
    }

    @Override
    public R addAminMenu(SysAdminMenuDto dto) {
        SysAdminMenu menu = ShunCommonUtils.beanMap(dto, SysAdminMenu.class);
        String menuId = IdUtil.objectId();
        menu.setMenuId(menuId);
        menu.setMenuPcodes(dto.getMenuPcode());
        menu.setMenuRoute(dto.getMenuUrl());
        boolean saveFlag = save(menu);
        return saveFlag ? R.suc() : RC.DB_ADD_ERROR.toR();
    }

    @Override
    public R pageAdminMenu(SysAdminMenuDto dto) {
        IPage<SysAdminMenu> menuIPage = page(dto.toPage(), new QueryWrapper<SysAdminMenu>());
        return R.suc(menuIPage);
    }

    @Override
    public R getBtnsByUser(String userId) {
        List<Map<String, Object>> btns = new ArrayList<>();
        if (userId.equals(UpmsConstant.SUPER_ADMIN_ID)) {
            btns = menuMapper.getBtnsByAdmin(UpmsConstant.MENU_LEVEL_THREE);
        } else {
            btns = menuMapper.getBtnsByUser(UpmsConstant.MENU_LEVEL_THREE, userId);
        }
        Map<String, Set<Map<String, Object>>> listMap = new HashMap<String, Set<Map<String, Object>>>();
        btns.stream().forEach(m -> {
            String pcode = m.get("pcode").toString();
            if (listMap.containsKey(pcode)) {
                Set<Map<String, Object>> codeSet = listMap.get(pcode);
                codeSet.add(btnMap(m));
            } else {
                Set<Map<String, Object>> codeSet = new HashSet<>();
                codeSet.add(btnMap(m));
                listMap.put(pcode, codeSet);
            }
        });
        return R.suc(listMap);
    }

    /**
     * menu转化btn
     *
     * @param menuMap
     * @return
     */
    public Map<String, Object> btnMap(Map<String, Object> menuMap) {
        Map<String, Object> btnMap = new HashMap<>();
        menuMap.forEach((k, v) -> {
            if (k.equals("code")) {
                int ch = v.toString().indexOf("_") + 1;
                String value = v.toString().substring(ch);
                if (value.equals(UpmsConstant.MENU_DEL) || value.equals(UpmsConstant.MENU_ADD)) {
                    btnMap.put("type", UpmsConstant.MENU_BTN_TYPE_TOP);
                } else {
                    btnMap.put("type", UpmsConstant.MENU_BTN_TYPE_IN);
                }
                btnMap.put(k, value);
            } else {
                btnMap.put(k, v);
            }
        });
        return btnMap;
    }

    @Override
    public R getMenusByUser() {
        String userId = StpUtil.getLoginIdAsString();
        log.debug("userId:{}", userId);
        List<SysMenuNode> nodes = new ArrayList<>();
        if (UpmsConstant.SUPER_ADMIN_ID.equals(userId)) {
            List<SysAdminMenu> parentMenus = new LambdaQueryChainWrapper<SysAdminMenu>(this.baseMapper).orderBy(true,true,SysAdminMenu::getMenuSort).eq(SysAdminMenu::getMenuLevel, UpmsConstant.MENU_LEVEL_ONE).list();
            List<SysAdminMenu> twoMenus = new LambdaQueryChainWrapper<SysAdminMenu>(this.baseMapper).orderBy(true,true,SysAdminMenu::getMenuSort).eq(SysAdminMenu::getMenuLevel, UpmsConstant.MENU_LEVEL_TWO).list();
            nodes = getNodes(parentMenus);
            nodes.forEach(n -> {
                n.setChildren(getChildernNode(n.getMenuId(), twoMenus));
            });
        } else {
            List<SysAdminMenu> parentMenus = menuMapper.getMenusByUser(UpmsConstant.MENU_LEVEL_ONE, userId);
            List<SysAdminMenu> twoMenus = menuMapper.getMenusByUser(UpmsConstant.MENU_LEVEL_TWO, userId);
            nodes = getNodes(parentMenus);
            nodes.forEach(n -> {
                n.setChildren(getChildernNode(n.getMenuId(), twoMenus));
            });
        }
        return R.suc(nodes);
    }

    @Override
    public R getMenuNameAndId() {
        List<Map<String, Object>> menuNameAndIds = list().stream().map(m -> {
            Map<String, Object> nameMap = new HashMap<String, Object>();
            nameMap.put("name", m.getMenuName());
            nameMap.put("id", m.getMenuId());
            return nameMap;
        }).collect(Collectors.toList());
        Map<String, Object> indexMenu = new HashMap<>();
        indexMenu.put("name", UpmsConstant.MENU_ROOT_NAME);
        indexMenu.put("id", UpmsConstant.MENU_ROOT_ID);
        menuNameAndIds.add(indexMenu);
        return R.suc(menuNameAndIds);
    }

    /**
     * menu转化node
     *
     * @param m
     * @return
     */
    public SysMenuNode getNode(SysAdminMenu m) {
        Map<String, Object> meta = new HashMap<>();
        meta.put("title", m.getMenuName());
        meta.put("icon", m.getMenuIcon());
        meta.put("code", m.getMenuCode());
        SysMenuNode node = SysMenuNode.builder().menuId(m.getMenuId()).parentId(m.getMenuParentId())
                .name(m.getMenuCode()).url(m.getMenuUrl()).meta(meta).build();
        return node;
    }

    /**
     * menu转化node
     *
     * @param menuId
     * @return
     */
    public List<SysMenuNode> getChildernNode(String menuId, List<SysAdminMenu> children) {
        List<SysMenuNode> childrenNodes = new ArrayList<>();
        children.stream().filter(m -> m.getMenuParentId().equals(menuId))
                .forEach(m -> {
                    childrenNodes.add(getNode(m));
                });
        return childrenNodes;
    }

    /**
     * menu转化node
     *
     * @param menus
     * @return
     */
    public List<SysMenuNode> getNodes(List<SysAdminMenu> menus) {
        List<SysMenuNode> nodes = menus.stream().distinct().map(m -> getNode(m)).collect(Collectors.toList());
        return nodes;
    }

    /**
     * 仅仅做二级目录处理
     *
     * @return
     */
    public List<MenuTreeNode> getTreeMenuNodes() {
        List<SysAdminMenu> oneLevels = new LambdaQueryChainWrapper<SysAdminMenu>(this.baseMapper)
                .eq(SysAdminMenu::getMenuLevel, UpmsConstant.MENU_LEVEL_ONE).orderBy(true, true, SysAdminMenu::getMenuSort)
                .list();
        List<SysAdminMenu> twoLevels = new LambdaQueryChainWrapper<SysAdminMenu>(this.baseMapper)
                .eq(SysAdminMenu::getMenuLevel, UpmsConstant.MENU_LEVEL_TWO).orderBy(true, true, SysAdminMenu::getMenuSort)
                .list();
        List<MenuTreeNode> menuTreeNodes = new ArrayList<>();
        oneLevels.stream().forEach(m -> {
            MenuTreeNode oneNode = MenuTreeNode.builder().nodeId(m.getMenuId()).nodeLabel(m.getMenuName()).build();
            List<MenuTreeNode> children = new ArrayList<MenuTreeNode>();
            twoLevels.stream().filter(t -> t.getMenuParentId().equals(m.getMenuId())).forEach(t -> {
                children.add(MenuTreeNode.builder().nodeId(t.getMenuId()).nodeLabel(t.getMenuName()).build());
            });
            oneNode.setChildren(children);
            menuTreeNodes.add(oneNode);
        });
        return menuTreeNodes;
    }

    @Override
    public R getMenuNodes() {
        QueryWrapper<SysAdminMenu> menuQueryWrapper = new QueryWrapper<SysAdminMenu>().orderByAsc("menu_sort");
        List<SysAdminMenu> sysAdminMenuList = list(menuQueryWrapper);
        List<SysAdminMenuNodesDto> nodesDtos = sysAdminMenuList.stream().map(m -> {
           return ShunCommonUtils.beanMap(m, SysAdminMenuNodesDto.class);
        }).collect(Collectors.toList());
        return R.suc(nodesDtos);
    }

    @Override
    public R getMenuNodesByMenuId(String menuId) {
        if(UpmsConstant.MENU_ROOT_ID.equals(menuId)){
           return R.suc(menuMapper.getMenuNode());
        }
        return R.suc(menuMapper.getMenuNodeById(menuId));
    }

    @Override
    public R delMenuByMenuId(String menuId) {

        QueryWrapper<SysAdminMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("menu_parent_id",menuId);
        List<SysAdminMenu> menus = list(queryWrapper);
       if(ObjectUtil.isEmpty(menus)){
           boolean flag = removeById(menuId);
           return flag?R.suc():R.error(UpmsConstant.DEL_ADMIN_MENU_ERROR);
       }
        return R.error(UpmsConstant.DEL_ADMIN_MENU_HAS_ERROR);
    }

    @Override
    public R editMenuByMenuId(SysAdminMenuDto dto) {
        UpdateWrapper<SysAdminMenu> sysAdminMenuUpdateWrapper = new UpdateWrapper<>();
        sysAdminMenuUpdateWrapper.eq("menu_id",dto.getMenuId());
        SysAdminMenu sysAdminMenu = ShunCommonUtils.beanMap(dto,SysAdminMenu.class);
        boolean flag = update(sysAdminMenu,sysAdminMenuUpdateWrapper);
        return flag?R.suc():R.error(UpmsConstant.EDIT_ADMIN_MENU_ERROR);
    }

    /**
     * 做递归目录处理
     *
     * @return
     */
    public List<MenuTreeNode> getTreeMenuNodes(List<MenuTreeNode> nodes, String nodeId) {
        List<MenuTreeNode> treeNodes = new ArrayList<>();
        if (ObjectUtil.isEmpty(nodes)) {
            nodes = new LambdaQueryChainWrapper<SysAdminMenu>(this.baseMapper).list().stream()
                    .map(m -> {
                        return MenuTreeNode.builder().nodePid(m.getMenuParentId()).
                                nodeId(m.getMenuId()).nodeLabel(m.getMenuName()).build();
                    })
                    .collect(Collectors.toList());
        }
        for (MenuTreeNode node : nodes) {
            String id = node.getNodeId();
            String pid = node.getNodePid();
            if (pid.equals(nodeId)) {
                List<MenuTreeNode> children = getTreeMenuNodes(nodes, id);
                node.setChildren(children);
                treeNodes.add(node);
            }
        }
        return treeNodes;
    }

    /**
     * 获取角色的按钮信息列表
     * @param roleId
     * @return
     */
    @Override
    public R getBtnIdsByRole(String roleId) {
        List<Map<String, Object>> btns = menuMapper.getBtnsByRole(UpmsConstant.MENU_LEVEL_THREE, roleId);
        List<String> menuIds = btns.stream().map( m -> m.get("menuId").toString()).collect(Collectors.toList());
        return R.suc(menuIds);
    }
}
